home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Libraries / stdwin / Ports / x11 / window.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-02-05  |  33.2 KB  |  1,531 lines  |  [TEXT/????]

  1. /* X11 STDWIN -- Window operations */
  2.  
  3. #include "x11.h"
  4. #include "llevent.h"
  5. #include <X11/Xutil.h> /* For Rectangle{In,Out,Part} */
  6.  
  7.  
  8. /* Margin size around inner window (space for scroll and menu bars) */
  9.  
  10. #define LMARGIN        16
  11. /*
  12. #define TMARGIN        (MIN((_wmf->ascent + _wmf->descent), 16) + 2)
  13. */
  14. #define TMARGIN        18
  15. #define RMARGIN        0
  16. #define BMARGIN        16
  17.  
  18. #define IMARGIN        0    /* Extra left/right margin in inner window */
  19.  
  20.  
  21. /* Size of outer window border */
  22.  
  23. #define OBORDER        2
  24.  
  25.  
  26. /* XXX IMARGIN and OBORDER should be settable with properties and command
  27.    line options.  Maybe the other margins as well. */
  28.  
  29.  
  30. /* Event masks */
  31.  
  32. /* Mask for 'wo' */
  33. #define OUTER_MASK    ( KeyPressMask \
  34.             | FocusChangeMask \
  35.             | EnterWindowMask \
  36.             | LeaveWindowMask \
  37.             | StructureNotifyMask \
  38.             )
  39.  
  40. /* Mask for other windows except 'wi' */
  41. #define OTHER_MASK    ( ButtonPressMask \
  42.             | ButtonReleaseMask \
  43.             | ButtonMotionMask \
  44.             | ExposureMask \
  45.             )
  46.  
  47.     
  48. /* Private globals */
  49.  
  50. static int def_h = 0, def_v = 0;
  51. static int def_width = 0, def_height = 0;
  52. static int def_hbar = 0;
  53. static int def_vbar = 1;
  54. static int def_mbar = 1;
  55.  
  56. #define DEF_WIDTH (def_width > 0 ? def_width : 40*wtextwidth("in", 2))
  57. #define DEF_HEIGHT (def_height > 0 ? def_height : 24*wlineheight())
  58.  
  59.  
  60. /* WINDOW list.
  61.    Each WINDOW must be registered here, so it can be found back
  62.    by _whichwin */
  63.  
  64. static WINDOW **winlist = 0;
  65. static int nwins = 0;
  66.  
  67.  
  68. /* Find a WINDOW pointer, given a Window.
  69.    Hunt through the WINDOW list, for each element comparing the given wid
  70.    with the wids of all (sub)Windows */
  71.  
  72. WINDOW *
  73. _whichwin(w)
  74.     register Window w;
  75. {
  76.     register int i;
  77.     
  78.     for (i = nwins; --i >= 0; ) {
  79.         register WINDOW *win = winlist[i];
  80.         register int j;
  81.         for (j = NSUBS; --j >= 0; ) {
  82.             if (w == win->subw[j].wid)
  83.                 return win;
  84.         }
  85.     }
  86.     _wdebug(2, "_whichwin: can't find Window %x", w);
  87.     return NULL;
  88. }
  89.  
  90.  
  91. /* Return some window */
  92.  
  93. WINDOW *
  94. _w_somewin()
  95. {
  96.     if (nwins <= 0)
  97.         return NULL;
  98.     return winlist[0];
  99. }
  100.  
  101.  
  102. /* Set the max size of windows created later (ignored for now) */
  103.  
  104. /*ARGSUSED*/
  105. void
  106. wsetmaxwinsize(width, height)
  107.     int width, height;
  108. {
  109. }
  110.  
  111.  
  112. /* Set the initial size of windows created later */
  113.  
  114. void
  115. wsetdefwinsize(width, height)
  116.     int width, height;
  117. {
  118.     def_width = width;
  119.     def_height = height;
  120. }
  121.  
  122. void
  123. wgetdefwinsize(pwidth, pheight)
  124.     int *pwidth, *pheight;
  125. {
  126.     *pheight = def_height;
  127.     *pwidth = def_width;
  128. }
  129.  
  130.  
  131. /* Set the initial position of windows created later */
  132.  
  133. void
  134. wsetdefwinpos(h, v)
  135.     int h, v;
  136. {
  137.     def_h = h;
  138.     def_v = v;
  139. }
  140.  
  141. void
  142. wgetdefwinpos(ph, pv)
  143.     int *ph, *pv;
  144. {
  145.     *ph = def_h;
  146.     *pv = def_v;
  147. }
  148.  
  149.  
  150. /* Set the scroll bar options */
  151.  
  152. void
  153. wsetdefscrollbars(need_hbar, need_vbar)
  154.     int need_hbar, need_vbar;
  155. {
  156.     def_hbar = need_hbar;
  157.     def_vbar = need_vbar;
  158. }
  159.  
  160. void
  161. wgetdefscrollbars(phbar, pvbar)
  162.     int *phbar, *pvbar;
  163. {
  164.     *phbar = def_hbar;
  165.     *pvbar = def_vbar;
  166. }
  167.  
  168.  
  169. /* Read a Bitmap from a file and convert it to a Pixmap.
  170.    XXX Actually I don't convert it to a Pixmap; this may mean that perhaps
  171.    you won't be able to set an icon on a color display, depending
  172.    on the intelligence of the window manager.
  173.    XXX Note that to fix this you must create separate functions to read
  174.    Bitmaps and Pixmaps, as Bitmaps have a real use (for icon masks). */
  175.  
  176. #define readpixmap readbitmap
  177.  
  178. /* Read a bitmap from file */
  179.  
  180. static Pixmap
  181. readbitmap(filename)
  182.     char *filename;
  183. {
  184.     unsigned int width, height;
  185.     int xhot, yhot;
  186.     Pixmap bitmap;
  187.     int err = XReadBitmapFile(_wd, RootWindowOfScreen(_ws), filename,
  188.         &width, &height, &bitmap, &xhot, &yhot);
  189.     if (err != BitmapSuccess) {
  190.         _wwarning("can't read bitmap file %s, error code %d",
  191.             filename, err);
  192.         return None;
  193.     }
  194.     return bitmap;
  195. }
  196.  
  197.  
  198. /* Forward */
  199. static bool _wmakesubwins _ARGS((WINDOW *win));
  200.  
  201.  
  202. /* Open a WINDOW.
  203.    Some defaults should only be used for the first window opened,
  204.    e.g., window geometry (otherwise all windows would overlay each other!)
  205.    and the "iconic" property.  Icon bitmaps will be used by all windows. */
  206.  
  207. WINDOW *
  208. wopen(title, drawproc)
  209.     char *title;
  210.     void (*drawproc)();
  211. {
  212.     static bool used_defaults;
  213.     WINDOW *win;
  214.     XSizeHints sizehints;
  215.     char *geom;
  216.     
  217.     /* Allocate zeroed storage for the WINDOW structure
  218.        and fill in the easy non-zero values */
  219.     win = (WINDOW*) calloc(sizeof(WINDOW), 1);
  220.     if (win == NULL) {
  221.         _werror("wopen: can't alloc storage for window");
  222.         return NULL;
  223.     }
  224.     win->drawproc = drawproc;
  225.     win->careth = win->caretv = -1;
  226.     win->attr = wattr;
  227.     win->tmargin = def_mbar ? TMARGIN : 0;
  228.     win->rmargin = RMARGIN;
  229.     win->bmargin = def_hbar ? BMARGIN : 0;
  230.     win->lmargin = def_vbar ? LMARGIN : 0;
  231.  
  232.     sizehints.x = def_h <= 0 ? 0 : def_h - win->lmargin - OBORDER;
  233.     sizehints.y = def_v <= 0 ? 0 : def_v - win->tmargin - OBORDER;
  234.     sizehints.width = DEF_WIDTH + win->lmargin + win->rmargin
  235.              + 2*IMARGIN;
  236.     sizehints.height = DEF_HEIGHT + win->tmargin + win->bmargin;
  237.     sizehints.flags = PSize;
  238.     if (def_h > 0 || def_v > 0)
  239.         sizehints.flags |= PPosition | USPosition;
  240.         /* USPosition added to fool twm */
  241.  
  242. #ifndef PRE_R4
  243.     /* Set base size and resize increment */
  244.     sizehints.base_width = win->lmargin + win->rmargin + 2*IMARGIN;
  245.     sizehints.base_height = win->tmargin + win->bmargin;
  246.     sizehints.width_inc = 1;
  247.     sizehints.height_inc = 1;
  248.     sizehints.flags |= PBaseSize | PResizeInc;
  249. #endif
  250.  
  251.     /* Parse user-specified geometry default.
  252.        This overrides what the application specified.
  253.        Note that the x and y stored internally are exclusive or borders,
  254.        while X geometries specify x and y including the border.
  255.        XXX Also note that the obsolete sizehints members x, y, width and
  256.        height are used later to actually create the window. */
  257.  
  258.     if (!used_defaults &&
  259.         (geom = _wgetdefault("geometry", "Geometry")) != NULL) {
  260.         unsigned int width, height;
  261.  
  262.         int flags = XParseGeometry(geom,
  263.             &sizehints.x, &sizehints.y, &width, &height);
  264.         if (flags & WidthValue)
  265.             sizehints.width = width
  266.                 + win->lmargin + win->rmargin
  267.                 + 2*IMARGIN;
  268.         if (flags & HeightValue)
  269.             sizehints.height = height
  270.                 + win->tmargin + win->bmargin;
  271.         if (flags & XNegative)
  272.             sizehints.x =
  273.                 WidthOfScreen(_ws) + sizehints.x
  274.                 - sizehints.width - OBORDER;
  275.         if (flags & YNegative)
  276.             sizehints.y =
  277.                 HeightOfScreen(_ws) + sizehints.y
  278.                 - sizehints.height - OBORDER;
  279.  
  280.         /* Use the user-specified size as the default
  281.            size for future windows */
  282.  
  283.         if (flags & WidthValue)
  284.             def_width = width;
  285.         if (flags & HeightValue)
  286.             def_height = height;
  287.  
  288.         /* If the user has given as position,
  289.            pretend a size is also given, otherwise
  290.            UWM will still ask for interactive
  291.            window placement.  I'm in good company:
  292.            "the" Toolkit also does this. */
  293.  
  294.         if (flags & (XValue|YValue))
  295.             sizehints.flags |= USPosition|USSize;
  296.         else if (flags & (WidthValue|HeightValue))
  297.             sizehints.flags |= USSize;
  298.  
  299. #ifndef PRE_R4
  300.         /* Derive the gravity hint from the geometry */
  301.  
  302.         if ((flags & XNegative) || (flags & YNegative)) {
  303.             sizehints.flags |= PWinGravity;
  304.             if (flags & XNegative) {
  305.                 if (flags & YNegative)
  306.                     sizehints.win_gravity =
  307.                         SouthEastGravity;
  308.                 else
  309.                     sizehints.win_gravity =
  310.                         NorthEastGravity;
  311.             }
  312.             else
  313.                 sizehints.win_gravity =
  314.                     SouthWestGravity;
  315.         }
  316. #endif            
  317.     }
  318.     
  319.     /* Set the initial geometry from the size hints just computed */
  320.     win->wo.border = OBORDER;
  321.     win->wo.x = sizehints.x + win->wo.border;
  322.     win->wo.y = sizehints.y + win->wo.border;
  323.     win->wo.width = sizehints.width;
  324.     win->wo.height = sizehints.height;
  325.     
  326.     /* Set the foreground and background pixel values */
  327.     win->fga = _w_fgcolor;
  328.     win->bga = _w_bgcolor;
  329.     win->fgo = _wgetpixel("menuForeground", "MenuForeground", _w_fgcolor);
  330.     win->bgo = _wgetpixel("menuBackground", "MenuBackground", _w_bgcolor);
  331.     
  332.     /* Create the outer Window */
  333.     if (!_wcreate(&win->wo, RootWindowOfScreen(_ws), 0, FALSE,
  334.         win->fgo, win->bgo)) {
  335.         FREE(win);
  336.         return NULL;
  337.     }
  338.     
  339.     /* Create the inner subWindows */
  340.     if (!_wmakesubwins(win)) {
  341.         FREE(win);
  342.         return NULL;
  343.     }
  344.     
  345.     /* Create the Graphics Contexts */
  346.     win->gc = _wgcreate(win->wo.wid, _wmf->fid, win->fgo, win->bgo);
  347.     win->gca = _wgcreate(win->wa.wid, _wf->fid, win->fga, win->bga);
  348.  
  349.     /* Set the plane mask so _winvert keeps working... */
  350.     XSetPlaneMask(_wd, win->gc, win->fgo ^ win->bgo);
  351.  
  352.     /* Change selected Window properties */
  353.     _wsetmasks(win);
  354.     _w_setgrayborder(win);
  355.     
  356.     /* Set the "invalid" region to empty (rely on Expose events) */
  357.     win->inval = XCreateRegion();
  358.     
  359.     /* Initialize the menu bar stuff */
  360.     _waddmenus(win);
  361.     
  362.     /* Set window properties */
  363.     
  364.     /* Set window and icon names */
  365.     {
  366.         char *windowname = title;
  367.         char *iconname = NULL;
  368.         char *p;
  369.         
  370.         /* Resources may override these for the first window */
  371.         if (!used_defaults) {
  372.             if ((p = _wgetdefault("title", "Title")) != NULL)
  373.                 windowname = iconname = p;
  374.             if ((p = _wgetdefault("iconName", "IconName")) != NULL)
  375.                 iconname = p;
  376.         }
  377.         
  378.         XStoreName(_wd, win->wo.wid, windowname);
  379.         /* Only store the icon name if specified -- the WM will
  380.            derive a default from the title otherwise. */
  381.         if (iconname != NULL)
  382.             XSetIconName(_wd, win->wo.wid, iconname);
  383.     }
  384.     
  385.     /* Set command line (computed by winitargs()) */
  386.     XChangeProperty(_wd, win->wo.wid,
  387.         XA_WM_COMMAND, XA_STRING, 8, PropModeReplace,
  388.         (unsigned char *)_wm_command, _wm_command_len);
  389.         /* XXX The ICCCM prescribes that exactly one window
  390.            of a given client has this property.  Later. */
  391.     
  392.     /* Set normal size hints (computed above) */
  393. #ifdef PRE_R4
  394.     XSetNormalHints(_wd, win->wo.wid, &sizehints);
  395. #else
  396.     /* XSetNormalHints carefully masks away the base size and
  397.        window gravity, so we must call XChangeProperty directly. */
  398.     /* XXX This is not correct on machines where int != long. Sigh. */
  399.     XChangeProperty(_wd, win->wo.wid,
  400.         XA_WM_NORMAL_HINTS, XA_WM_SIZE_HINTS, 32, PropModeReplace,
  401.         (unsigned char *) &sizehints, sizeof sizehints / 4);
  402. #endif
  403.     
  404.     /* Set WM Hints */
  405.     {
  406.         XWMHints wmhints;
  407.         char *value;
  408.         wmhints.flags = InputHint | StateHint;
  409.         wmhints.input = _wgetbool("input", "Input", 1);
  410.         if (!used_defaults &&
  411.             _wgetbool("iconic", "Iconic", 0))
  412.             wmhints.initial_state = IconicState;
  413.         else
  414.             wmhints.initial_state = NormalState;
  415.         if (!used_defaults && (value =
  416.             _wgetdefault("iconGeometry", "IconGeometry"))
  417.                 != NULL) {
  418.             unsigned int width, height;
  419.             int flags = XParseGeometry(value,
  420.                 &wmhints.icon_x, &wmhints.icon_y,
  421.                 &width, &height);
  422.             if (flags & XNegative)
  423.                 wmhints.icon_x =
  424.                     WidthOfScreen(_ws) - wmhints.icon_x;
  425.             if (flags & YNegative)
  426.                 wmhints.icon_y =
  427.                     HeightOfScreen(_ws) - wmhints.icon_y;
  428.             if (flags & (XValue|YValue)) {
  429.                 wmhints.flags |= IconPositionHint;
  430.                 _wdebug(1, "icon pos: %d,%d",
  431.                     wmhints.icon_x, wmhints.icon_y);
  432.             }
  433.             else
  434.                 _wdebug(1, "no icon pos");
  435.         }
  436.         value = _wgetdefault("iconBitmap", "IconBitmap");
  437.         if (value != NULL)  {
  438.             wmhints.icon_pixmap = readpixmap(value);
  439.             if (wmhints.icon_pixmap != None)
  440.                 wmhints.flags |= IconPixmapHint;
  441.         }
  442.         value = _wgetdefault("iconMask", "IconMask");
  443.         if (value != NULL)  {
  444.             wmhints.icon_mask = readbitmap(value);
  445.             if (wmhints.icon_mask != None)
  446.                 wmhints.flags |= IconMaskHint;
  447.         }
  448.         /* XXX What about window groups? */
  449.         XSetWMHints(_wd, win->wo.wid, &wmhints);
  450.     }
  451.     
  452.     /* Set class (same as strings used by _wgetdefault() */
  453.     {
  454.         XClassHint classhint;
  455.         classhint.res_name = _wprogname;
  456.         classhint.res_class = "Stdwin";
  457.         XSetClassHint(_wd, win->wo.wid, &classhint);
  458.     }
  459.     
  460.     /* Set client machine */
  461.     XChangeProperty(_wd, win->wo.wid,
  462.         XA_WM_CLIENT_MACHINE, XA_STRING, 8, PropModeReplace,
  463.         (unsigned char *)_whostname, strlen(_whostname));
  464.     
  465.     /* Set protocols property */
  466.     {
  467.         static Atom protocols[] = {
  468.             0 /*XA_WM_DELETE_WINDOW*/,
  469.         };
  470.         protocols[0] = _wm_delete_window;
  471.         XChangeProperty(_wd, win->wo.wid,
  472.             _wm_protocols, XA_ATOM, 32, PropModeReplace,
  473.             (unsigned char *)protocols,
  474.             sizeof(protocols) / sizeof(protocols[0]));
  475.     }
  476.     
  477.     /* Store the WINDOW pointer in the list of windows */
  478.     L_APPEND(nwins, winlist, WINDOW *, win);
  479.     
  480.     /* Now we're ready, finally show the window, on top of others */
  481.     XMapRaised(_wd, win->wo.wid);
  482.     
  483.     /* Note that we've used the once-only defaults */
  484.     used_defaults = TRUE;
  485.     
  486.     /* Don't forget to return the WINDOW pointer */
  487.     return win;
  488. }
  489.  
  490.  
  491. /* Make a window the active window -- ICCCM version.
  492.    - De-iconify.
  493.    - Raise the window.
  494.    Any events that may follow from this are handled later when we get them.
  495. */
  496.  
  497. void
  498. wsetactive(win)
  499.     WINDOW *win;
  500. {
  501.     XMapRaised(_wd, win->wo.wid); /* The ICCCM way to de-iconify */
  502.     XRaiseWindow(_wd, win->wo.wid);
  503. }
  504.  
  505.  
  506. /* Fetch a color, by name */
  507.  
  508. COLOR
  509. wfetchcolor(cname)
  510.     char *cname;
  511. {
  512.     return (COLOR) _w_fetchpixel(cname, (unsigned long)BADCOLOR);
  513. }
  514.  
  515.  
  516. /* Get a pixel value from the resource database */
  517.  
  518. unsigned long
  519. _wgetpixel(resname, resclassname, defpixel)
  520.     char *resname;
  521.     char *resclassname;
  522.     unsigned long defpixel;
  523. {
  524.     char *cname;
  525.     Colormap cmap;
  526.     XColor hard, exact;
  527.     
  528.     cname = _wgetdefault(resname, resclassname);
  529.     if (cname == NULL)
  530.         return defpixel;
  531.     return _w_fetchpixel(cname, defpixel);
  532. }
  533.  
  534.  
  535. /* Translate a color name or #RGB spec into a pixel value */
  536.  
  537. unsigned long
  538. _w_fetchpixel(cname, defpixel)
  539.     char *cname;
  540.     unsigned long defpixel;
  541. {
  542.     Colormap cmap;
  543.     XColor hard, exact;
  544.     
  545.     cmap = DefaultColormapOfScreen(_ws);
  546.     if (!XParseColor(_wd, cmap, cname, &exact)) {
  547.         _wdebug(1, "%s: no such color", cname);
  548.         return defpixel;
  549.     }
  550.     hard = exact;
  551.     if (!XAllocColor(_wd, cmap, &hard)) {
  552.         _wdebug(1, "%s: can't allocate color cell", cname);
  553.         return defpixel;
  554.     }
  555.     return hard.pixel;
  556. }
  557.  
  558.  
  559. /* Return a gray pixmap */
  560.  
  561. Pixmap
  562. _w_gray() {
  563. #include <X11/bitmaps/gray>
  564. /* defines gray_bits, gray_width, gray_height */
  565.     
  566.     static Pixmap gray;
  567.     
  568.     if (gray == 0) {
  569.         gray = XCreatePixmapFromBitmapData(_wd,
  570.             RootWindowOfScreen(_ws),
  571.             gray_bits, gray_width, gray_height,
  572.             BlackPixelOfScreen(_ws),
  573.             WhitePixelOfScreen(_ws),
  574.             DefaultDepthOfScreen(_ws));
  575.     }
  576.     
  577.     return gray;
  578. }
  579.  
  580.  
  581. /* Rasters used by _w_raster below */
  582.  
  583. #define raster_width 4
  584. #define raster_height 4
  585. static char raster_bits[][4] = {
  586.     {0x00, 0x00, 0x00, 0x00},
  587.     {0x01, 0x00, 0x00, 0x00},
  588.     {0x01, 0x00, 0x04, 0x00},
  589.     {0x08, 0x00, 0x04, 0x01},
  590.     {0x05, 0x00, 0x05, 0x00},
  591.     {0x01, 0x0a, 0x00, 0x0a},
  592.     {0x05, 0x02, 0x05, 0x08},
  593.     {0x05, 0x02, 0x05, 0x0a},
  594.     {0x05, 0x0a, 0x05, 0x0a},
  595.     {0x07, 0x0a, 0x05, 0x0a},
  596.     {0x07, 0x0a, 0x0d, 0x0a},
  597.     {0x0a, 0x0f, 0x05, 0x0e},
  598.     {0x0f, 0x0a, 0x0f, 0x0a},
  599.     {0x07, 0x0f, 0x0b, 0x0e},
  600.     {0x0e, 0x0f, 0x0b, 0x0f},
  601.     {0x0f, 0x0f, 0x0f, 0x0b},
  602.     {0xff, 0xff, 0xff, 0xff},
  603. };
  604. #define NRASTERS (sizeof raster_bits / sizeof raster_bits[0])
  605.  
  606. /* Return a raster of a certain percentage */
  607.  
  608. Pixmap
  609. _w_raster(percent)
  610.     int percent;
  611. {
  612.     static Pixmap raster[NRASTERS];
  613.     int i = (percent * NRASTERS + 50) / 100;
  614.  
  615.     if (i < 0)
  616.         i = 0;
  617.     if (i >= NRASTERS)
  618.         i = NRASTERS-1;
  619.     if (raster[i] == 0) {
  620.         raster[i] = XCreateBitmapFromData(_wd,
  621.             RootWindowOfScreen(_ws),
  622.             raster_bits[i], raster_width, raster_height);
  623.     }
  624.     return raster[i];
  625. }
  626.  
  627.  
  628. /* Set the border pixmap of a window to a gray pattern */
  629.  
  630. void
  631. _w_setgrayborder(win)
  632.     WINDOW *win;
  633. {
  634.     XSetWindowBorderPixmap(_wd, win->wo.wid, _w_gray());
  635. }
  636.  
  637.  
  638. /* Create a Graphics Context using the given Window and Font ids and colors.
  639.    Don't set the font if Font id is zero. */
  640.  
  641. GC
  642. _wgcreate(wid, fid, fg, bg)
  643.     Window wid;
  644.     Font fid;
  645.     unsigned long fg, bg;
  646. {
  647.     int mask = GCForeground|GCBackground;
  648.     XGCValues v;
  649.     
  650.     v.foreground = fg;
  651.     v.background = bg;
  652.     if (fid != 0) {
  653.         v.font = fid;
  654.         mask |= GCFont;
  655.     }
  656.     return XCreateGC(_wd, wid, mask, &v);
  657. }
  658.  
  659.  
  660. /* Create a Window for a given windata struct and set its event mask.
  661.    If map is TRUE, also map it.
  662.    Initially, a window is not dirty (it'll get Expose events for that) */
  663.  
  664. bool
  665. _wcreate1(wp, parent, cursor, map, fg, bg, nowm)
  666.     struct windata *wp;
  667.     Window parent;
  668.     int cursor;
  669.     bool map;
  670.     unsigned long fg, bg;
  671.     bool nowm;
  672. {
  673.     XSetWindowAttributes attributes;
  674.     unsigned long valuemask;
  675.  
  676.     /* Don't create empty windows */
  677.     if (wp->width == 0 || wp->height == 0) {
  678.         wp->wid = None;
  679.         return TRUE;
  680.     }
  681.  
  682.     valuemask = CWBackPixel|CWBorderPixel|CWBitGravity|CWBackingStore;
  683.     attributes.background_pixel = bg;
  684.     attributes.border_pixel = fg;
  685.     attributes.bit_gravity = NorthWestGravity;
  686.     if (nowm) {
  687.         attributes.override_redirect = 1;
  688.         valuemask |= CWOverrideRedirect;
  689.     }
  690.     attributes.backing_store = NotUseful; /* Seems to be Harmful... */
  691.  
  692.     if (cursor > 0) {
  693.         attributes.cursor = XCreateFontCursor(_wd, cursor);
  694.         valuemask |= CWCursor;
  695.     }
  696.     
  697.     /* We must subtract border width from x and y before
  698.        passing them to WCreateSimpleWindow, since
  699.        they refer to the upper left corner of the border! */
  700.     
  701.     wp->wid = XCreateWindow(
  702.             _wd,
  703.             parent,
  704.             wp->x - wp->border,    /* x */
  705.             wp->y - wp->border,    /* y */
  706.             wp->width,
  707.             wp->height,
  708.             wp->border,        /* border width */
  709.             CopyFromParent,        /* depth */
  710.             InputOutput,        /* class */
  711.             CopyFromParent,        /* visual */
  712.             valuemask,
  713.             &attributes
  714.         );
  715.     if (!wp->wid) {
  716.         _werror("_wcreate: can't create (sub)Window");
  717.         return FALSE;
  718.     }
  719.     _wdebug(2, "_wcreate: wid=0x%x", wp->wid);
  720.     if (map)
  721.         XMapWindow(_wd, wp->wid);
  722.     wp->dirty = FALSE;
  723.     return TRUE;
  724. }
  725.  
  726.  
  727. /* Set the save-under property for a window given by a windata struct */
  728.  
  729. void
  730. _wsaveunder(wp, flag)
  731.     struct windata *wp;
  732.     Bool flag;
  733. {
  734.     static int saveUnder = -1;
  735.     XSetWindowAttributes attrs;
  736.  
  737.     if (wp->wid == None)
  738.         return;
  739.     
  740.     /* The user may explicitly turn off save-unders by specifying
  741.         Stdwin*SaveUnder: off
  742.        since they are broken on some servers */
  743.     
  744.     if (saveUnder < 0) {
  745.         /* First time here: check resource database */
  746.         saveUnder = _wgetbool("saveUnder", "SaveUnder", 1);
  747.         if (!saveUnder)
  748.             _wdebug(1, "user doesn't want save-unders");
  749.     }
  750.     
  751.     if (!saveUnder)
  752.         return;
  753.     
  754.     attrs.save_under = flag;
  755.     XChangeWindowAttributes(_wd, wp->wid, CWSaveUnder, &attrs);
  756. }
  757.  
  758.  
  759. /* Set gravity for a window given by a windata struct */
  760.  
  761. static void
  762. _wgravity(wp, grav)
  763.     struct windata *wp;
  764.     int grav;
  765. {
  766.     XSetWindowAttributes attrs;
  767.     if (wp->wid == None)
  768.         return;
  769.     attrs.win_gravity = grav;
  770.     XChangeWindowAttributes(_wd, wp->wid, CWWinGravity, &attrs);
  771. }
  772.  
  773.  
  774. /* Move and resize a window given by a windata struct */
  775.  
  776. void
  777. _wmove(wp)
  778.     struct windata *wp;
  779. {
  780.     if (wp->wid == None)
  781.         return;
  782.     XMoveResizeWindow(_wd, wp->wid,
  783.         wp->x - wp->border, wp->y - wp->border, wp->width, wp->height);
  784. }
  785.  
  786.  
  787. /* (Re)compute the sizes and positions of all subwindows.
  788.    Note a check (in SZ) to prevent windows ever to get a size <= 0 */
  789.  
  790. static
  791. _wsizesubwins(win)
  792.     WINDOW *win;
  793. {
  794.     int bmargin = win->wi.height - win->doc.height - win->wa.y;
  795.     int rmargin = win->wi.width - IMARGIN - win->doc.width - win->wa.x;
  796.  
  797. #define SZ(elem, nx, ny, nw, nh, nb) \
  798.         (win->elem.x = (nx), \
  799.         win->elem.y = (ny), \
  800.         win->elem.width = (nw) > 0 ? (nw) : 1, \
  801.         win->elem.height = (nh) > 0 ? (nh) : 1, \
  802.         win->elem.border = (nb))
  803.  
  804.     /* Interior window in the middle */
  805.     SZ(wi, win->lmargin, win->tmargin,
  806.         win->wo.width - win->lmargin - win->rmargin,
  807.         win->wo.height - win->tmargin - win->bmargin, 0);
  808.     /* Menu bar at the top */
  809.     if (win->tmargin)
  810.         SZ(mbar, 0, 0, win->wo.width, win->tmargin - IBORDER, IBORDER);
  811.     else
  812.         SZ(mbar, 0, 0, 0, 0, 0);
  813.     /* Vbar left */
  814.     if (win->lmargin)
  815.         SZ(vbar, 0, win->wi.y, win->lmargin - IBORDER,
  816.            win->wi.height, IBORDER);
  817.     else
  818.         SZ(vbar, 0, 0, 0, 0, 0);
  819.     /* Hbar at the bottom */
  820.     if (win->bmargin)
  821.         SZ(hbar, win->wi.x, win->wo.height - win->bmargin + IBORDER,
  822.            win->wi.width, win->bmargin - IBORDER, IBORDER);
  823.     else
  824.         SZ(hbar, 0, 0, 0, 0, 0);
  825.  
  826. #undef SZ
  827.     
  828.     /* The document window (wa) is sized differently.
  829.        If it fits in the window, it is made the same size
  830.        and aligned at (0,0) no questions asked.
  831.        Otherwise, it is moved so that the window never shows more
  832.        outside it than before (if at all possible). */
  833.     
  834.     if (win->doc.width <= win->wi.width - 2*IMARGIN) {
  835.         win->wa.x = IMARGIN;
  836.         win->wa.width = win->wi.width - 2*IMARGIN;
  837.     }
  838.     else {
  839.         CLIPMIN(rmargin, IMARGIN);
  840.         CLIPMIN(win->wa.x, win->wi.width - win->wa.width - rmargin);
  841.         CLIPMAX(win->wa.x, IMARGIN);
  842.         win->wa.width = win->doc.width;
  843.         CLIPMIN(win->wa.width, win->wi.width - win->wa.x);
  844.     }
  845.     if (win->doc.height <= win->wi.height) {
  846.         win->wa.y = 0;
  847.         win->wa.height = win->wi.height;
  848.     }
  849.     else {
  850.         CLIPMIN(bmargin, 0);
  851.         CLIPMIN(win->wa.y, win->wi.height - win->wa.height - bmargin);
  852.         CLIPMAX(win->wa.y, 0);
  853.         win->wa.height = win->doc.height;
  854.         CLIPMIN(win->wa.height, win->wi.height - win->wa.y);
  855.     }
  856.     win->wa.border = IMARGIN;
  857. }
  858.  
  859.  
  860. /* Create the permanently visible subwindows.
  861.    Return TRUE if all creations succeeded.
  862.    The inner window is created after all bars, so it lies on top,
  863.    and will receive clicks in its border */
  864.  
  865. static bool
  866. _wmakesubwins(win)
  867.     WINDOW *win;
  868. {
  869.     Window w = win->wo.wid;
  870.     unsigned long fg = win->fgo, bg = win->bgo;
  871.     
  872.     _wsizesubwins(win);
  873.     if (!(    _wcreate(&win->mbar, w, XC_arrow, TRUE, fg, bg) &&
  874.         _wcreate(&win->vbar, w, XC_sb_v_double_arrow, TRUE, fg, bg) &&
  875.         _wcreate(&win->hbar, w, XC_sb_h_double_arrow, TRUE, fg, bg) &&
  876.         _wcreate(&win->wi, w, 0, TRUE, fg, bg) &&
  877.         _wcreate(&win->wa, win->wi.wid, XC_crosshair, TRUE,
  878.             win->bga, win->bga)))
  879.         return FALSE;
  880.     _wgravity(&win->hbar, SouthWestGravity);
  881.     return TRUE;
  882. }
  883.  
  884.  
  885. /* Resize all subwindows and move them to their new positions.
  886.    The application and current menu windows (WA, MWIN) are not resized.
  887.    The application window may be moved, however, to prevent exposing
  888.    parts outside the document that weren't visible earlier. */
  889.  
  890. void
  891. _wmovesubwins(win)
  892.     WINDOW *win;
  893. {
  894.     int i;
  895.     _wsizesubwins(win);
  896.     
  897.     for (i = 1; i <= WA; ++i)
  898.         _wmove(&win->subw[i]);
  899.     
  900.     /* Invalidate scroll bars after a resize */
  901.     win->hbar.dirty = win->vbar.dirty = _w_dirty = TRUE;
  902. }
  903.  
  904.  
  905. /* Set normal event masks for all (sub)Windows of a WINDOW */
  906.  
  907. void
  908. _wsetmasks(win)
  909.     WINDOW *win;
  910. {
  911.     int i;
  912.     
  913.     XSelectInput(_wd, win->wo.wid, OUTER_MASK);
  914.     for (i = 1; i <= WA; ++i) {
  915.         if (win->subw[i].wid != 0)
  916.             XSelectInput(_wd, win->subw[i].wid,
  917.                 (i == WI) ? NoEventMask : OTHER_MASK);
  918.     }
  919. }
  920.  
  921.  
  922. /* Generate any pending size event. */
  923.  
  924. bool
  925. _w_doresizes(ep)
  926.     EVENT *ep;
  927. {
  928.     int i;
  929.  
  930.     for (i = nwins; --i >= 0; ) {
  931.         WINDOW *win = winlist[i];
  932.         if (win->resized) {
  933.             win->resized = FALSE;
  934.             ep->type = WE_SIZE;
  935.             ep->window = win;
  936.             if (i == 0)
  937.                 _w_resized = FALSE;
  938.             return TRUE;
  939.         }
  940.     }
  941.     _w_resized = FALSE;
  942.     return FALSE;
  943. }
  944.  
  945.  
  946. /* Forward */
  947. static bool update _ARGS((WINDOW *win, EVENT *ep));
  948.  
  949.  
  950. /* Perform any pending window updates.
  951.    If the application subwindow needs an update,
  952.    either call its draw procedure or generate a WE_DRAW event
  953.    in the given event record (and then stop).
  954.    Return TRUE if an event was generated */
  955.  
  956. bool
  957. _w_doupdates(ep)
  958.     EVENT *ep;
  959. {
  960.     int i;
  961.  
  962.     for (i = nwins; --i >= 0; ) {
  963.         if (update(winlist[i], ep)) {
  964.             if (i == 0)
  965.                 _w_dirty = FALSE;
  966.             return TRUE;
  967.         }
  968.     }
  969.     _w_dirty = FALSE;
  970.     return FALSE;
  971. }
  972.  
  973. void
  974. wupdate(win)
  975.     WINDOW *win;
  976. {
  977.     (void) update(win, (EVENT *)NULL);
  978. }
  979.  
  980. /* Update any parts of a window that need updating.
  981.    If the application window needs redrawing and there is no drawproc
  982.    and the 'ep' argument is non-nil,
  983.    construct a DRAW event and return TRUE. */
  984.  
  985. static bool
  986. update(win, ep)
  987.     WINDOW *win;
  988.     EVENT *ep;
  989. {
  990.     bool ret = FALSE;
  991.     
  992.     if (win->mbar.dirty)
  993.         _wdrawmbar(win);
  994.     if (win->hbar.dirty)
  995.         _wdrawhbar(win);
  996.     if (win->vbar.dirty)
  997.         _wdrawvbar(win);
  998.     win->mbar.dirty = win->hbar.dirty = win->vbar.dirty = FALSE;
  999.     /* wi and wo have nothing that can be drawn! */
  1000.     
  1001.     if (win->wa.dirty && (win->drawproc != NULL || ep != NULL)) {
  1002.         XRectangle clip;
  1003.         int left, top, right, bottom;
  1004.         XClipBox(win->inval, &clip);
  1005.         left = clip.x;
  1006.         top = clip.y;
  1007.         right = left + clip.width;
  1008.         bottom = top + clip.height;
  1009.         CLIPMIN(left, -win->wa.x);
  1010.         CLIPMIN(top, -win->wa.y);
  1011.         CLIPMAX(right, win->wi.width - win->wa.x);
  1012.         CLIPMAX(bottom, win->wi.height - win->wa.y);
  1013.         _wdebug(3, "clip: (%d,%d) to (%d,%d)",
  1014.             left, top, right, bottom);
  1015.         if (left < right && top < bottom) {
  1016.             _whidecaret(win);
  1017.             if (win->drawproc != NULL) {
  1018.                 /* A bug in X11R2 XSetRegion prevents this
  1019.                    from working: */
  1020. #ifndef PRE_R3
  1021.                 /* Version for R3 or later */
  1022.                 XSetRegion(_wd, win->gca, win->inval);
  1023. #else
  1024.                 /* Version for R2 */
  1025.                 XSetClipRectangles(_wd, win->gca,
  1026.                     0, 0, &clip, 1, Unsorted);
  1027. #endif
  1028.                 wbegindrawing(win);
  1029.                 werase(left, top, right, bottom);
  1030.                 (*win->drawproc)(win,
  1031.                     left, top, right, bottom);
  1032.                 wenddrawing(win);
  1033.                 XSetClipMask(_wd, win->gca, (Pixmap)None);
  1034.             }
  1035.             else {
  1036.                 XClearArea(_wd, win->wa.wid,
  1037.                     clip.x, clip.y,
  1038.                     clip.width, clip.height, FALSE);
  1039.                 ep->type = WE_DRAW;
  1040.                 ep->window = win;
  1041.                 ep->u.area.left = left;
  1042.                 ep->u.area.top = top;
  1043.                 ep->u.area.right = right;
  1044.                 ep->u.area.bottom = bottom;
  1045.                 ret = TRUE;
  1046.             }
  1047.             _wshowcaret(win);
  1048.         }
  1049.         XDestroyRegion(win->inval);
  1050.         win->inval = XCreateRegion();
  1051.         win->wa.dirty = FALSE;
  1052.     }
  1053.     return ret;
  1054. }
  1055.  
  1056.  
  1057. /* Close a window */
  1058.  
  1059. void
  1060. wclose(win)
  1061.     WINDOW *win;
  1062. {
  1063.     int i;
  1064.     for (i = 0; i < nwins; ++i) {
  1065.         if (winlist[i] == win)
  1066.             break;
  1067.     }
  1068.     if (i >= nwins) {
  1069.         _werror("wclose: unknown window");
  1070.         return;
  1071.     }
  1072.     L_REMOVE(nwins, winlist, WINDOW *, i);
  1073.     _w_deactivate(win);
  1074.     _w_delmenus(win);
  1075.     XFreeGC(_wd, win->gc);
  1076.     XFreeGC(_wd, win->gca);
  1077.     XDestroyWindow(_wd, win->wo.wid);
  1078.     XFlush(_wd); /* Make the effect immediate */
  1079.     FREE(win);
  1080. }
  1081.  
  1082.  
  1083. /* Change a window's title */
  1084.  
  1085. void
  1086. wsettitle(win, title)
  1087.     WINDOW *win;
  1088.     char *title;
  1089. {
  1090.     XStoreName(_wd, win->wo.wid, title);
  1091.     XFlush(_wd); /* Make the effect immediate */
  1092.     /* The icon name will not change */
  1093. }
  1094.  
  1095.  
  1096. /* Return a window's current title -- straight from the window property */
  1097.  
  1098. char *
  1099. wgettitle(win)
  1100.     WINDOW *win;
  1101. {
  1102.     static char *title = NULL;
  1103.     
  1104.     if (title != NULL)
  1105.         free(title); /* Free result of previous call */
  1106.     title = NULL; /* Just in case */
  1107.     if (!XFetchName(_wd, win->wo.wid, &title))
  1108.         _wwarning("wgettitle: no title set");
  1109.     return title;
  1110. }
  1111.  
  1112.  
  1113. /* Change a window's icon name */
  1114.  
  1115. void
  1116. wseticontitle(win, title)
  1117.     WINDOW *win;
  1118.     char *title;
  1119. {
  1120.     XSetIconName(_wd, win->wo.wid, title);
  1121. }
  1122.  
  1123.  
  1124. /* Return a window's current icon name -- straight from the window property */
  1125.  
  1126. char *
  1127. wgeticontitle(win)
  1128.     WINDOW *win;
  1129. {
  1130.     static char *title = NULL;
  1131.     
  1132.     if (title != NULL)
  1133.         free(title); /* Free result of previous call */
  1134.     title = NULL; /* Just in case */
  1135.     if (!XGetIconName(_wd, win->wo.wid, &title))
  1136.         _wdebug(1, "wgeticontitle: no icon name set");
  1137.         /* This may occur normally so don't make it a warning */
  1138.     return title;
  1139. }
  1140.  
  1141.  
  1142. /* Get a window's size.
  1143.    This is really the size of the visible part of the document. */
  1144.  
  1145. void
  1146. wgetwinsize(win, pwidth, pheight)
  1147.     WINDOW *win;
  1148.     int *pwidth, *pheight;
  1149. {
  1150.     *pwidth = win->wi.width - 2*IMARGIN;
  1151.     *pheight = win->wi.height;
  1152. }
  1153.  
  1154.  
  1155. /* Get a window's position relative to the root */
  1156.  
  1157. void
  1158. wgetwinpos(win, ph, pv)
  1159.     WINDOW *win;
  1160.     int *ph, *pv;
  1161. {
  1162.     Window child;
  1163.     
  1164.     if (!XTranslateCoordinates(    _wd,
  1165.                     win->wi.wid,
  1166.                     RootWindowOfScreen(_ws),
  1167.                     IMARGIN, 0,
  1168.                     ph, pv,
  1169.                     &child)) {
  1170.         
  1171.         _wwarning("wgetwinpos: XTranslateCoordinates failed");
  1172.         *ph = 0;
  1173.         *pv = 0;
  1174.     }
  1175. }
  1176.  
  1177.  
  1178. /* Set a window's size */
  1179.  
  1180. void
  1181. wsetwinsize(win, width, height)
  1182.     WINDOW *win;
  1183.     int width, height;
  1184. {
  1185.     width = width + win->lmargin + win->rmargin + 2*IMARGIN;
  1186.     height = height + win->tmargin + win->bmargin;
  1187.     XResizeWindow(_wd, win->wo.wid, width, height);
  1188.     XFlush(_wd); /* Make the effect immediate */
  1189. }
  1190.  
  1191.  
  1192. /* Set a window's position */
  1193.  
  1194. void
  1195. wsetwinpos(win, h, v)
  1196.     WINDOW *win;
  1197.     int h, v;
  1198. {
  1199.     h = h - win->lmargin - OBORDER;
  1200.     v = v - win->tmargin - OBORDER;
  1201.     XMoveWindow(_wd, win->wo.wid, h, v);
  1202.     XFlush(_wd); /* Make the effect immediate */
  1203. }
  1204.  
  1205.  
  1206. /* "Change" part of a document, i.e., post a WE_DRAW event */
  1207.  
  1208. void
  1209. wchange(win, left, top, right, bottom)
  1210.     WINDOW *win;
  1211.     int left, top, right, bottom;
  1212. {
  1213.     _wdebug(3, "wchange: %d %d %d %d", left, top, right, bottom);
  1214.     if (left < right && top < bottom) {
  1215.         XRectangle r;
  1216.         r.x = left;
  1217.         r.y = top;
  1218.         r.width = right - left;
  1219.         r.height = bottom - top;
  1220.         XUnionRectWithRegion(&r, win->inval, win->inval);
  1221.         win->wa.dirty = TRUE;
  1222.         _w_dirty = TRUE;
  1223.     }
  1224. }
  1225.  
  1226.  
  1227. /* "Scroll" part of a document, i.e., copy bits and erase the place
  1228.    where they came from.  May cause WE_DRAW events if source bits are
  1229.    covered. */
  1230.  
  1231. void
  1232. wscroll(win, left, top, right, bottom, dh, dv)
  1233.     WINDOW *win;
  1234.     int left, top, right, bottom;
  1235.     int dh, dv;
  1236. {
  1237.     int src_x = left, src_y = top;
  1238.     int dest_x = left, dest_y = top;
  1239.     int width = right - left - ABS(dh);
  1240.     int height = bottom - top - ABS(dv);
  1241.     
  1242.     if (dh == 0 && dv == 0 || left >= right || top >= bottom)
  1243.         return;
  1244.     
  1245.     if (dh < 0)
  1246.         src_x += -dh;
  1247.     else
  1248.         dest_x += dh;
  1249.     if (dv < 0)
  1250.         src_y += -dv;
  1251.     else
  1252.         dest_y += dv;
  1253.     
  1254.     _wdebug(2, "wscroll: src(%d,%d)size(%d,%d)dest(%d,%d)",
  1255.         src_x, src_y, width, height, dest_x, dest_y);
  1256.     if (width > 0 && height > 0) {
  1257.         _whidecaret(win);
  1258.         XCopyArea(_wd, win->wa.wid, win->wa.wid, win->gca,
  1259.               src_x, src_y, width, height, dest_x, dest_y);
  1260.         _wshowcaret(win);
  1261.     }
  1262.     
  1263.     if (XRectInRegion(win->inval, left, top, right-left, bottom-top)
  1264.                             != RectangleOut) {
  1265.         /* Scroll the overlap between win->inval and the
  1266.            scrolled rectangle:
  1267.             scroll := <the entire scrolling rectangle>
  1268.             overlap := inval * scroll
  1269.             inval -:= overlap
  1270.             shift overlap by (dh, dv)
  1271.             overlap := overlap * scroll
  1272.             inval +:= overlap
  1273.         */
  1274.         Region scroll = XCreateRegion();
  1275.         Region overlap = XCreateRegion();
  1276.         XRectangle r;
  1277.         r.x = left;
  1278.         r.y = top;
  1279.         r.width = right-left;
  1280.         r.height = bottom-top;
  1281.         XUnionRectWithRegion(&r, scroll, scroll);
  1282.         XIntersectRegion(win->inval, scroll, overlap);
  1283.         XSubtractRegion(win->inval, overlap, win->inval);
  1284.         XOffsetRegion(overlap, dh, dv);
  1285.         XIntersectRegion(overlap, scroll, overlap);
  1286.         XUnionRegion(win->inval, overlap, win->inval);
  1287.         XDestroyRegion(overlap);
  1288.         XDestroyRegion(scroll);
  1289.  
  1290.         /* There's still a bug left: exposure events in the queue
  1291.            (like GraphicsExposures caused be previous scrolls!)
  1292.            should be offset as well, bu this is too complicated
  1293.            to fix right now... */
  1294.     }
  1295.     
  1296.     /* Clear the bits scrolled in */
  1297.     
  1298.     if (dh > 0)
  1299.         XClearArea(_wd, win->wa.wid,
  1300.             left, top, dh, bottom-top, FALSE);
  1301.     else if (dh < 0)
  1302.         XClearArea(_wd, win->wa.wid,
  1303.             right+dh, top, -dh, bottom-top, FALSE);
  1304.     if (dv > 0)
  1305.         XClearArea(_wd, win->wa.wid,
  1306.             left, top, right-left, dv, FALSE);
  1307.     else if (dv < 0)
  1308.         XClearArea(_wd, win->wa.wid,
  1309.             left, bottom+dv, right-left, -dv, FALSE);
  1310. }
  1311.  
  1312.  
  1313. /* Change the "origin" of a window (position of document, really) */
  1314.  
  1315. void
  1316. wsetorigin(win, orgh, orgv)
  1317.     WINDOW *win;
  1318.     int orgh, orgv;
  1319. {
  1320.     bool moveit = FALSE;
  1321.     
  1322.     CLIPMIN(orgh, 0);
  1323.     CLIPMIN(orgv, 0);
  1324.     if (win->wa.x != IMARGIN - orgh) {
  1325.         win->hbar.dirty = moveit = TRUE;
  1326.         win->wa.x = IMARGIN - orgh;
  1327.     }
  1328.     if (win->wa.y != -orgv) {
  1329.         win->vbar.dirty = moveit = TRUE;
  1330.         win->wa.y = -orgv;
  1331.     }
  1332.     if (moveit)
  1333.         XMoveWindow(_wd, win->wa.wid,
  1334.                 IMARGIN - orgh - win->wa.border,
  1335.                 -orgv - win->wa.border);
  1336. }
  1337.  
  1338.  
  1339. /* Get the "origin" (see above) of a window */
  1340.  
  1341. void
  1342. wgetorigin(win, ph, pv)
  1343.     WINDOW *win;
  1344.     int *ph, *pv;
  1345. {
  1346.     *ph = IMARGIN - win->wa.x;
  1347.     *pv = -win->wa.y;
  1348. }
  1349.  
  1350.  
  1351. /* Set the document size.  Zero means don't use a scroll bar */
  1352.  
  1353. void
  1354. wsetdocsize(win, width, height)
  1355.     WINDOW *win;
  1356.     int width, height;
  1357. {
  1358.     bool dirty = FALSE;
  1359.     
  1360.     CLIPMIN(width, 0);
  1361.     CLIPMIN(height, 0);
  1362.     if (win->doc.width != width) {
  1363.         win->doc.width = width;
  1364.         if (width <= win->wo.width - IMARGIN) {
  1365.             win->wa.x = IMARGIN;
  1366.             win->wa.width = win->wi.width;
  1367.         }
  1368.         else {
  1369.             win->wa.width = width;
  1370.             CLIPMIN(win->wa.width, win->wi.width - win->wa.x);
  1371.         }
  1372.         win->hbar.dirty = dirty = TRUE;
  1373.     }
  1374.     if (win->doc.height != height) {
  1375.         win->doc.height = height;
  1376.         if (height <= win->wo.height) {
  1377.             win->wa.y = 0;
  1378.             win->wa.height = win->wi.height;
  1379.         }
  1380.         else {
  1381.             win->wa.height = height;
  1382.         }
  1383.         win->vbar.dirty = dirty = TRUE;
  1384.     }
  1385.     if (dirty) {
  1386.         _w_dirty = TRUE;
  1387.         _wmove(&win->wa);
  1388.     }
  1389. }
  1390.  
  1391.  
  1392. /* Return the document size last set by wsetdocsize() */
  1393.  
  1394. void
  1395. wgetdocsize(win, pwidth, pheight)
  1396.     WINDOW *win;
  1397.     int *pwidth, *pheight;
  1398. {
  1399.     *pwidth = win->doc.width;
  1400.     *pheight = win->doc.height;
  1401. }
  1402.  
  1403.  
  1404. /* Change the cursor for a window */
  1405.  
  1406. void
  1407. wsetwincursor(win, cursor)
  1408.     WINDOW *win;
  1409.     CURSOR *cursor;
  1410. {
  1411.     Cursor c;
  1412.     if (cursor == NULL)
  1413.         c = None;
  1414.     else
  1415.         c = (Cursor) cursor;
  1416.     XDefineCursor(_wd, win->wa.wid, c);
  1417.     XFlush(_wd); /* Make the effect immediate */
  1418. }
  1419.  
  1420.  
  1421. /* Scroll the document in the window to ensure that the given rectangle
  1422.    is visible, if at all possible.  Don't scroll more than necessary. */
  1423.  
  1424. void
  1425. wshow(win, left, top, right, bottom)
  1426.     WINDOW *win;
  1427.     int left, top, right, bottom;
  1428. {
  1429.     int orgh, orgv;
  1430.     int winwidth, winheight;
  1431.     int extrah, extrav;
  1432.     
  1433.     _wdebug(3, "wshow: %d %d %d %d", left, top, right, bottom);
  1434.  
  1435.     wgetorigin(win, &orgh, &orgv);
  1436.     wgetwinsize(win, &winwidth, &winheight);
  1437.     
  1438.     if (left >= orgh &&
  1439.         top >= orgv &&
  1440.         right <= orgh + winwidth &&
  1441.         bottom <= orgv + winheight)
  1442.         return; /* Already visible */
  1443.     
  1444.     extrah = (winwidth - (right - left)) / 2;
  1445.     CLIPMAX(extrah, win->doc.width - right);
  1446.     CLIPMIN(extrah, 0);
  1447.     orgh = right + extrah - winwidth;
  1448.     CLIPMAX(orgh, left);
  1449.     CLIPMIN(orgv, 0);
  1450.     
  1451.     extrav = (winheight - (bottom - top)) / 2;
  1452.     CLIPMAX(extrav, win->doc.height - bottom);
  1453.     CLIPMIN(extrav, 0);
  1454.     orgv = bottom + extrav - winheight;
  1455.     CLIPMAX(orgv, top);
  1456.     CLIPMIN(orgv, 0);
  1457.     
  1458.     wsetorigin(win, orgh, orgv);
  1459. }
  1460.  
  1461.  
  1462. /* Sound the bell (beep) */
  1463.  
  1464. void
  1465. wfleep()
  1466. {
  1467.     XBell(_wd, 0);
  1468. }
  1469.  
  1470.  
  1471. /* Helper functions for the menu mananger: */
  1472.  
  1473. _waddtoall(mp)
  1474.     MENU *mp;
  1475. {
  1476.     int i;
  1477.     
  1478.     for (i = nwins; --i >= 0; )
  1479.         wmenuattach(winlist[i], mp);
  1480. }
  1481.  
  1482.  
  1483. _wdelfromall(mp)
  1484.     MENU *mp;
  1485. {
  1486.     int i;
  1487.     
  1488.     for (i = nwins; --i >= 0; )
  1489.         wmenudetach(winlist[i], mp);
  1490. }
  1491.  
  1492.  
  1493. /* Helper function for the timer manager: */
  1494.  
  1495. WINDOW *
  1496. _wnexttimer()
  1497. {
  1498.     int i;
  1499.     WINDOW *cand = NULL;
  1500.     
  1501.     for (i = nwins; --i >= 0; ) {
  1502.         WINDOW *win = winlist[i];
  1503.         long t = win->timer;
  1504.         if (t != 0) {
  1505.             if (cand == NULL || t < cand->timer)
  1506.                 cand = win;
  1507.         }
  1508.     }
  1509.     return cand;
  1510. }
  1511.  
  1512.  
  1513. /* Delete all windows -- called by wdone() */
  1514.  
  1515. _wkillwindows()
  1516. {
  1517.     while (nwins > 0)
  1518.         wclose(winlist[nwins-1]);
  1519. }
  1520.  
  1521.  
  1522. /* X11-specific hack: get the window ID of a window's document window.
  1523.    This is used by the Ghostscript bridge. */
  1524.  
  1525. long
  1526. wgetxwindowid(win)
  1527.     WINDOW *win;
  1528. {
  1529.     return win->wa.wid;
  1530. }
  1531.